package jn.chen.utils.img;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Random;
import java.util.regex.Pattern;

/**
 * @Description 爬取图片的工具类
 * @Author 三文鱼先生
 * @Data 2023/5/6 11:42
 */
public class WallHavenDownloadToDir {

    /**
     * @Description 下载对应的图片地址到指定的目录下
     * @Param filePath 存储的文价目录
     * @Param imgUrl 下载的图片url
     * @Return {@link boolean} 是否下载成功
     * @Author 三文鱼先生
     * @Date 2023/5/9 14:58
     **/
    public static void main(String[] args) {
        downImages("F:\\img\\", "https://wallpapershome.com/nature");
    }
    private static boolean downImages(String filePath, String imgUrl) {
        String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36";
        // 若指定文件夹没有，则先创建
        File dir = new File(filePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }


        // 截取图片文件名
        String fileName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1, imgUrl.length());

        try {
            // 文件名里面可能有中文或者空格，所以这里要进行处理。但空格又会被URLEncoder转义为加号
            String urlTail = URLEncoder.encode(fileName, "UTF-8");
            // 因此要将加号转化为UTF-8格式的%20
            imgUrl = imgUrl.substring(0, imgUrl.lastIndexOf('/') + 1) + urlTail.replaceAll("\\+", "\\%20");

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 写出的路径 如果已存在就不再下载
        File file = new File(filePath + File.separator + fileName);
        if(file.exists()) {
            System.out.println("该图片已下载。");
            return true;
        }

        try {
            //随机暂停几秒 太过频繁会被识别成爬虫 导致抓取不成功
            Thread.sleep(new Random().nextInt(3)*1000);
            //连接对应的url
            URL url = new URL(imgUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestProperty("User-agent", userAgent);//伪装报头
            connection.setConnectTimeout(20 * 1000);

            InputStream in = connection.getInputStream();
            System.out.println("图片大小为：" + in.available());
            BufferedOutputStream out = new BufferedOutputStream(
                    new FileOutputStream(file)
            );
            byte[] buf = new byte[1024];
            int size;
            while (-1 != (size = in.read(buf))) {
                out.write(buf, 0, size);
            }
            out.close();
            in.close();
            return true;
        } catch (IOException e) {
            System.out.println("下载图片时遇到未知错误。");
            return false;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @Description 根据对应的url 下载其中的所有图片
     * @Param filePath 保存的文件路劲
     * @Param url WallHaven对应的地址
     * @Return {@link boolean} 是否下载成功
     * @Author 三文鱼先生
     * @Date 2023/5/9 15:02
     **/
    private static boolean getImage(String filePath, String url) {
        //伪装的报头
        String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36";

        try {
            // 利用Jsoup获得连接
            Connection connect = Jsoup.connect(url)
                    .userAgent(userAgent);//伪装报头
            // 得到Document对象
            Document document = connect.get();
            // 查找所有img标签
            Elements imgs = document.getElementsByTag("a");
            String pattern = "https://wallhaven.cc/w/.*";
            //每次仅仅获取一个
            boolean result = false;
            // 遍历img标签并获得src的属性
            for (Element element : imgs) {
                //获取每个img标签URL "abs:"表示绝对路径
                String imgSrc = element.attr("abs:href");
                // 打印URL
                boolean isMatch = Pattern.matches(pattern, imgSrc);
                if (isMatch){
                    System.out.println("下载链接："+imgSrc);
                    Connection con = Jsoup.connect(imgSrc)
                            .userAgent(userAgent)
                            .timeout(10*1000);//伪装报头;
                    Document doc = con.get();
                    Elements pic = doc.getElementsByTag("img");
                    System.out.println(pic);
                    System.out.println("开始下载");
                    for(Element p : pic)
                    {
                        Element picSrc = p.getElementById("wallpaper");
                        if(picSrc!=null)
                        {
                            String picsrc = picSrc.attr("abs:src");
                            System.out.println("图片链接："+picsrc);
                            result = downImages(filePath, picsrc);
                            if(
                                    result
                            ) {
                                System.out.println("下载一张");
                            } else {
                                //只要有一张下载不成功则重新来 但是已经下载的不会再进行下载
                                return false;
                            }
                        }
                    }
                }
            }
            return result;
        } catch (IOException e) {
            System.out.println("获取图片链接时遇到未知错误");
            return false;
        }
    }

    /**
     * @Description 循环一百次 直到爬取成功
     * @Param filePath 图片存储地址
     * @Param url WallHaven里面的对应搜索网址
     * @Return {@link boolean} 是否成功
     * @Author 三文鱼先生
     * @Date 2023/5/9 15:04
     **/
    public static boolean downloadImageWithUrl(String filePath,String url) {
        try {
            for (int i = 0; i < 100; i++) {
                //每个界面随机暂停五秒 防止太过频繁被识别成爬虫
                Thread.sleep(new Random().nextInt(5)*1000);
                //获取对应url的图片
                if(getImage(filePath ,url)) {
                    //下载成功则不再执行循环
                    break;
                }
            }
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

}
